Powershell scripts/Storage Price Estimation Script/get-azStorageMetrics.ps1 (236 lines of code) (raw):
<#
.DESCRIPTION
The script will get estimated ingress metrics on Azure Files and Azure Blob files for supported V2 Storage Accounts with file containers across
all subscriptions in a tenant based on the ingress metric, which is in bytes.
- The ingress metric used in this script is based on the last 30 days at a 5 minute interval
- Overall this estimate is a ballpark and not to be expected as 100% accurate measure of file size on upload
- The script will output the totals and export the data to a csv file
.PARAMETER all
Get estimates for all storage accounts in the Tenant
.PARAMETER managementGroupName
An optional name of a managment group to scope the script to.
.PARAMETER subscriptionId
An optional string array of Subscritpion Ids to scope the script to.
.PARAMETER resourceGroupName
An optional resource group name to get all storage accounts in a resource group.
.PARAMETER storageAccountName
An optional storage account name to get estimates for a single storage account.
.EXAMPLE
Get estimates for all storage accounts in the Tenant
.\get-azStorageMetrics.ps1 -all
.EXAMPLE
Get estimates for all storage accounts in a management group you specify
.\get-azStorageMetrics.ps1 -managementGroupName "Finance"
.EXAMPLE
Get estimates for all storage accounts in Subscriptions you specify
# Single Subscription
.\get-azStorageMetrics.ps1 -subscriptionId '98aaxxab-0ef8-48e2-8397-a0101e0712e3'
# Multiple Subscriptions
.\get-azStorageMetrics.ps1 -subscriptionId '98aaxxab-0ef8-48e2-8397-a0101e0712e3,adaxxe68-375e-4210-be3a-c6cacebf41c5'
.EXAMPLE
Get estimates for all storage accounts in a resource group you specify
.\get-azStorageMetrics.ps1 -resourceGroupName "production accounts" -subscriptionId 'adaxxe68-375e-4210-be3a-c6cacebf41c5'
.EXAMPLE
Get estimates for a single storage account
.\get-azStorageMetrics.ps1 -storageAccountName "customeruploads" -resourceGroupName 'production accounts' -subscriptionId 'adaxxe68-375e-4210-be3a-c6cacebf41c5'
#>
param(
[CmdletBinding(DefaultParameterSetName="all")]
[Parameter(Mandatory=$true, ParameterSetName = 'all')]
[switch]$all,
[Parameter(Mandatory=$true, ParameterSetName = 'mgscope')]
[string]$managementGroupName,
[Parameter(Mandatory=$true, ParameterSetName = 'resourcegroupscope')]
[Parameter(Mandatory=$true, ParameterSetName = 'storageAccountScope')]
[Parameter(Mandatory=$true, ParameterSetName = 'subscope')]
[string]$subscriptionId,
[Parameter(Mandatory=$true, ParameterSetName = 'resourcegroupscope')]
[Parameter(Mandatory=$true, ParameterSetName = 'storageAccountScope')]
[string]$resourceGroupName,
[Parameter(Mandatory=$true, ParameterSetName = 'storageAccountScope')]
[string]$storageAccountName
)
# List Prices and Caculations
$defenderForStoragePerAccountPrice = 10
$overageTransactionsPrice = 0.1492
$overageTransactionLimit = 73000000
$malwareScanningPerGBPrice = .15
$requiredModules = 'Az.Accounts', 'Az.Storage', 'Az.Monitor'
$availableModules = Get-Module -ListAvailable -Name $requiredModules
$modulesToInstall = $requiredModules | where-object {$_ -notin $availableModules.Name}
ForEach ($module in $modulesToInstall){
Write-Host "Installing Missing PowerShell Module: $module" -ForegroundColor Yellow
Install-Module $module -force
}
# Load Latest Version
ForEach ($module in $requiredModules){
Remove-Module $module -Force -Confirm:$false -ErrorAction SilentlyContinue
(Get-Module -Name $module -ListAvailable | Sort-Object -Property Version)[-1] | Import-Module
}
# Connect to Azure if not already connected
If(!(Get-AzContext)){
Write-Host 'Connecting to Azure' -ForegroundColor Yellow
Connect-AzAccount -WarningAction SilentlyContinue | Out-Null
}
function Get-StorageAccounts {
param (
$subscriptions
)
$storageAccounts = @()
ForEach ($subscription in $subscriptions){
$subStorageAccounts = $null
Write-Host ('Getting All Storage Accounts in the {0} Subscription' -f $subscription.Name) -ForegroundColor Yellow
Set-AzContext -SubscriptionId $subscription.id | Out-Null
$subStorageAccounts = Get-AzStorageAccount | Where Kind -like 'StorageV2'
ForEach ($storageAccount in $subStorageAccounts){
$storageAccount | Add-Member -MemberType NoteProperty -Name 'Subscription' -Value $subscription.Name -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'SubscriptionId' -Value $subscription.Id -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'SubscriptionTenantId' -Value $subscription.TenantId -Force -ErrorAction SilentlyContinue
}
$storageAccounts += $subStorageAccounts
}
$storageAccounts
}
# Get storage accounts based on parameters
If ($PSCmdlet.ParameterSetName -like 'all') {
Write-Host "Scope: $($PSCmdlet.ParameterSetName)"
$subscriptions = Get-AzSubscription | where State -like 'Enabled' -WarningAction SilentlyContinue
$storageAccounts = Get-StorageAccounts -subscriptions $subscriptions
}
If ($PSCmdlet.ParameterSetName -like 'mgscope'){
Write-Host "Scope: $($PSCmdlet.ParameterSetName)"
$mg = Get-AzManagementGroup -GroupName $managementGroupName -Recurse -Expand -WarningAction SilentlyContinue
# Get All Subscriptions in the parent management group supplied
$mgSubs = @()
$mgSubs += Get-AzManagementGroupSubscription -GroupName $managementGroupName -WarningAction SilentlyContinue
# Get all Subscriptions in all child management groups
If ($mg.Children){
$childMg = $true
$childrenMgs = $mg.children | where Type -eq 'Microsoft.Management/managementGroups'
while($childMg) {
$childMg = $false
ForEach ($childrenMg in $childrenMgs){
If ($childrenMg.Children){
$childMg = $true
$childrenMgs = $childrenMg.Children | where Type -eq 'Microsoft.Management/managementGroups'
}
$mgSubs += Get-AzManagementGroupSubscription -GroupName $childrenMg.Name -WarningAction SilentlyContinue
}
}
}
$subscriptions = @()
$mgSubs | % {$subscriptions += Get-AzSubscription -SubscriptionId $_.Id.split('/')[-1] -WarningAction SilentlyContinue}
$storageAccounts = Get-StorageAccounts -subscriptions $subscriptions
}
If ($PSCmdlet.ParameterSetName -like 'subscope'){
Write-Host "Scope: $($PSCmdlet.ParameterSetName)"
If ($subscriptionId -match ','){
$subscriptions += $subscriptionId.split(',').trim() | % {Get-AzSubscription -SubscriptionId $_ -WarningAction SilentlyContinue}
}else{
$subscriptions += $subscriptionId | % {Get-AzSubscription -SubscriptionId $_ -WarningAction SilentlyContinue}
}
$storageAccounts = Get-StorageAccounts -subscriptions $subscriptions
}
If ($PSCmdlet.ParameterSetName -like 'resourcegroupscope'){
Write-Host "Scope: $($PSCmdlet.ParameterSetName)"
$subscriptions = Get-AzSubscription -SubscriptionId $subscriptionId
$storageAccounts = Get-StorageAccounts -subscriptions $subscriptions | where ResourceGroupName -Like $resourceGroupName
}
If ($PSCmdlet.ParameterSetName -like 'storageAccountScope') {
Write-Host "Scope: $($PSCmdlet.ParameterSetName)"
$subscriptions = Get-AzSubscription -SubscriptionId $subscriptionId
$storageAccounts = Get-StorageAccounts -subscriptions $subscriptions | Where-Object {$_.ResourceGroupName -Like $resourceGroupName -and $_.StorageAccountName -like $storageAccountName}
}
$report = @()
# Blob Specific metrics to determine accurate put operations of content
$blobMetricFilter = (New-AzMetricFilter -Dimension 'ApiName' -Operator eq -Value 'PutBlob','CopyBlob','PutBlock','PutBlockFromURL','AppendFile','FlushFile','CreatePathFile' -WarningAction SilentlyContinue)
# Get the related metrics for each Storage Account
Write-Host ('Found a total of {0} storage Accounts' -f $storageAccounts.Count) -ForegroundColor Yellow
ForEach ($storageAccount in $storageAccounts){
If((Get-AzContext).Subscription.Id -notlike $storageAccount.SubscriptionId){
Set-AzContext -subscriptionId $storageAccount.SubscriptionId | Out-Null
}
$totalBlobIngress30dayBytes = $null
$totalBlobIngress30dayMB = $null
$totalBlobIngress30dayGB = $null
$blobIngress = $null
$totalBlobIngress = 0
$blobTransactions = $null
$totalBlobTransactions = 0
$fileTransactions = $null
$totalFileTransactions = 0
$totalTransactions30day = $null
$transactionOverageCost = 0
$totalTransactionsOverages30day = 0
Write-Host ('Getting metrics for storage account: {0} in Resource Group: {1} Subscription: {2} in Tenant: {3}' -f $storageAccount.StorageAccountName, $storageAccount.ResourceGroupName, $storageAccount.Subscription, $storageAccount.SubscriptionTenantId) -ForegroundColor Yellow
# Get blob ingress in bytes over the past 30 days
$blobIngress = Get-AzMetric -ResourceId $($storageAccount.id + "/blobservices/default") -MetricName Ingress -MetricFilter $blobMetricFilter -AggregationType Total -StartTime $((Get-Date).AddMonths(-1)) -EndTime $(Get-Date) -WarningAction SilentlyContinue
# Get Transactions over the past 30 days
$fileTransactions = Get-AzMetric -ResourceId $($storageAccount.id + "/fileservices/default") -MetricName Transactions -AggregationType Total -StartTime $((Get-Date).AddMonths(-1)) -EndTime $(Get-Date) -WarningAction SilentlyContinue
$blobTransactions = Get-AzMetric -ResourceId $($storageAccount.id + "/blobservices/default") -MetricName Transactions -AggregationType Total -StartTime $((Get-Date).AddMonths(-1)) -EndTime $(Get-Date) -WarningAction SilentlyContinue
# Get Totals on transactions and blob ingress
$blobIngress.Data.Total | % {$totalBlobIngress += $_}
$fileTransactions.Data.Total | % {$totalFileTransactions += $_}
$blobTransactions.Data.Total | % {$totalBlobTransactions += $_}
$totalTransactions30day = $totalFileTransactions + $totalBlobTransactions
$totalBlobIngress30dayBytes = $totalBlobIngress
$totalBlobIngress30dayMB = [math]::round([decimal]$totalBlobIngress/1000/1000,6)
$totalBlobIngress30dayGB = [math]::round([decimal]$totalBlobIngress/1000/1000/1000,6)
# Calculate any overage costs for transactions
If ($totalTransactions30day -gt $overageTransactionLimit){
$totalTransactionsOverages30day = $totalTransactions30day - $transactionOverageLimit
$transactionOverageCost = ($totalTransactionsOverages30day / 1000000) * $overageTransactionsPrice
}
$storageAccount | Add-Member -MemberType NoteProperty -Name 'totalTransactions30day' -Value $totalTransactions30day -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'totalTransactionsOverages30day' -Value $totalTransactionsOverages30day -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'totalBlobIngress30dayBytes' -Value $totalBlobIngress30dayBytes -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'totalBlobIngress30dayMB' -Value $totalBlobIngress30dayMB -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'totalBlobIngress30dayGB' -Value $totalBlobIngress30dayGB -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'defenderForStorageCost' -Value $defenderForStoragePerAccountPrice -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'transactionOverageCost' -Value $transactionOverageCost -Force -ErrorAction SilentlyContinue
$storageAccount | Add-Member -MemberType NoteProperty -Name 'malwareScanningCost' -Value $($totalBlobIngress30dayGB * $malwareScanningPerGBPrice) -Force -ErrorAction SilentlyContinue
Write-Host (' {0} totalTransactions30day: {1}' -f $storageAccount.StorageAccountName, $totalTransactions30day) -ForegroundColor Yellow
Write-Host (' {0} totalBlobIngress30dayBytes: {1}, totalBlobIngress30dayMB:{2} totalBlobIngress30dayGB: {3},' -f $storageAccount.StorageAccountName, $totalBlobIngress30dayBytes, $totalBlobIngress30dayMB, $totalBlobIngress30dayGB) -ForegroundColor Yellow
}
$report += $storageAccounts | Select StorageAccountName, SubscriptionTenantId, Subscription, SubscriptionId, ResourceGroupName, totalTransactions30day, totalTransactionsOverages30day, totalBlobIngress30dayBytes, totalBlobIngress30dayMB, totalBlobIngress30dayGB,
defenderForStorageCost, transactionOverageCost, malwareScanningCost
# All Storage Account Totals
$totals = @{
numberOfSubscriptions = ($report.Subscription | Get-Unique | Measure-Object).Count
numberOfStorageAccounts = ($report.StorageAccountName | Measure-Object).Count
totalTransactions30day = ($report.totalTransactions30day | Measure-Object -Sum).Sum
totalTransactionsOverages30day = ($report.totalTransactionsOverages30day | Measure-Object -Sum).Sum
allAccountsTotalBlobIngress30dayBytes = ($report.totalBlobIngress30dayBytes | Measure-Object -Sum).Sum
allAccountsTotalBlobIngress30dayMB = ($report.totalBlobIngress30dayMB | Measure-Object -Sum).Sum
allAccountsTotalBlobIngress30dayGB = ($report.totalBlobIngress30dayGB | Measure-Object -Sum).Sum
allAccountsTotaldefenderForStorageCost = ($report.defenderForStorageCost | Measure-Object -Sum).Sum
allAccountsTotaltransactionOverageCost = ($report.transactionOverageCost | Measure-Object -Sum).Sum
allAccountsTotalmalwareScanningCost = ($report.malwareScanningCost | Measure-Object -Sum).Sum
}
# Adding Some formatting to make the CSV look pretty
$report += [PSCustomObject]@{
StorageAccountName = ''
SubscriptionTenantId = ''
}
$report += [PSCustomObject]@{
StorageAccountName = 'Total Category'
SubscriptionTenantId = 'Total Value'
}
$totalsObj = $totals.GetEnumerator() | Sort Name -Descending | % {
[PSCustomObject]@{
StorageAccountName = $_.key
SubscriptionTenantId = $_.Value
}
}
$report += $totalsObj
Write-Host ('Found a Total of {0} storage accounts in {1} Subscriptions. The values below represent the estimated totals for all storage accounts' -f $totals.numberOfStorageAccounts, $totals.numberOfSubscriptions) -ForegroundColor Green
Write-Host ('Total Transactions Over 30 Days: {0}' -f $totals.totalTransactions30day) -ForegroundColor Green
Write-Host ('Total Transactions Oververage Over 30 Days: {0}' -f $totals.totalTransactionsOverages30day) -ForegroundColor Green
Write-Host ('Total Blob Ingress Over 30 Days (Bytes): {0}' -f $totals.allAccountsTotalBlobIngress30dayBytes) -ForegroundColor Green
Write-Host ('Total Blob Ingress Over 30 Days (MB): {0}' -f $totals.allAccountsTotalBlobIngress30dayMB) -ForegroundColor Green
Write-Host ('Total Blob Ingress Over 30 Days (GB): {0}' -f $totals.allAccountsTotalBlobIngress30dayGB) -ForegroundColor Green
Write-Host ('Total Monthly Defender for Storage Costs: {0}' -f $totals.allAccountsTotaldefenderForStorageCost) -ForegroundColor Blue
Write-Host ('Total Monthly Transactions Overage Costs: {0}' -f $totals.allAccountsTotaltransactionOverageCost) -ForegroundColor Blue
Write-Host ('Total Monthly Malware Scanning Costs: {0}' -f $totals.allAccountsTotalmalwareScanningCost) -ForegroundColor Blue
$report | Export-CSV -Path .\defenderforstorage_estimates.csv -Force
Write-Host ('CSV file created with estimates: {0}\{1}' -f $(pwd).path, 'defenderforstorage_estimates.csv') -ForegroundColor Yellow